<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head> 
 <title>screenBox</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  
<script src="http://code.jquery.com/jquery-latest.js"></script>

<script type="text/javascript">/* Effects */


</script>

<script type="text/javascript">/* Prepare screens and actors */
var draggbleActor = null, selectedActor = null, //selecteds = [],

	characterPrefixId = 'view',
	wscreenW = null , wscreenH = null,
	
	screenW = 853, screenH = 480,

	workScale = 0.3,
	screenBorderW=1,
	incMoveActor = 1, incMoveActorCtrl = 10;

function fitScreens(){
	screenW = parseInt(document.getElementById('screenW').value) || screenW;	
	screenH = parseInt(document.getElementById('screenH').value) || screenH;
	workScale = parseFloat(document.getElementById('workScale').value) || workScale;
	screenBorderW = parseInt(document.getElementById('screenBorderW').value) || screenBorderW;

	wscreenW = screenW*workScale;
	wscreenH = screenH*workScale;
	$('#view_screen').css({width:screenW+'px', height:screenH+'px', 'border-width':screenBorderW+'px'});
	$('#work_screen').css({width:wscreenW+'px', height:wscreenH+'px', 'border-width':screenBorderW+'px'});
	$('#effects_panel').css({ width:screenW+'px',
		height:window.innerHeight-screenH-$('#setting_panel')[0].offsetHeight+'px', overflow: 'auto'
	});
}

function selectActors( event, el ){
	if( !event.ctrlKey ){
		$( '.selectedActor' ).removeClass('selectedActor');
		$( el ).addClass('selectedActor');
	}else $( el ).toggleClass('selectedActor');
	
	selectedActor = el;
}

function selectCharacters( excludeElem ){
	var result = [];
	$( '.selectedActor' ).each(function(){
		if(this == excludeElem) return;//исключенный элемент
		var actorEl = this, id = actorEl.id, preId = characterPrefixId || 'view';
		result.push( document.getElementById( preId+id ) );
	});
	return result;
}
function applyCharacters( func ){
	Array.prototype.forEach.call( selectCharacters(), func, false );
}
	
function moveCharacter( actorEl ){
	var id = actorEl.id, preId = characterPrefixId || 'view',
		chrtrEl = document.getElementById( preId+id ),
		top = actorEl.offsetTop-screenBorderW, viewTop=top/workScale+'px',
		left = actorEl.offsetLeft-screenBorderW, viewLeft=left/workScale+'px';
	chrtrEl.style.top = viewTop;
	chrtrEl.style.left = viewLeft;		
};

function moveGroup( excludeElem, shiftEl ){
	$( '.selectedActor' ).each(function(){
		if(this == excludeElem) return;//исключенный элемент
		var actorEl = this, id = actorEl.id, preId = characterPrefixId || 'view';
		actorEl.style.top = parseInt(actorEl.style.top)+shiftEl.shiftTop+'px';
		actorEl.style.left = parseInt(actorEl.style.left)+shiftEl.shiftLeft+'px';
		var top = actorEl.offsetTop-screenBorderW, viewTop=top/workScale+'px',
			left = actorEl.offsetLeft-screenBorderW, viewLeft=left/workScale+'px',
			chrtrEl = document.getElementById( preId+id );
		chrtrEl.style.top = viewTop;
		chrtrEl.style.left = viewLeft;		
	});
};

function fitActorsByCharacters( excludeElem ){
	$( '.character' ).each(function(){
		if( this == excludeElem ) return;//исключенный элемент
		
		var chrtrEl = this, id = chrtrEl.id, preId = characterPrefixId || 'view',
			actorId = ( id ).replace( preId, '' ),
			actorEl = document.getElementById( actorId ),
			top = chrtrEl.offsetTop-screenBorderW, workTop=top*workScale+'px',
			left = chrtrEl.offsetLeft-screenBorderW, workLeft=left*workScale+'px',
			width = chrtrEl.offsetWidth, workWidth=(width*workScale || 1)+'px',
			height = chrtrEl.offsetHeight, workHeight=(height*workScale || 1)+'px';
		//невидимый элемент	
		if( chrtrEl.style.display=='none' ) { 
			actorEl.style.opacity = .4;return;
		} else
			actorEl.style.opacity = 1;
			
		actorEl.style.top = workTop;
		actorEl.style.left = workLeft;
		actorEl.style.width = workWidth;
		actorEl.style.height = workHeight;
	});
};

function resizeCharacter( actorEl, characterPrefixId ){
	var id = actorEl.id, preId = characterPrefixId || 'view',
		width = actorEl.offsetWidth, viewWidth=width/workScale+'px',
		height = actorEl.offsetHeight, viewHeight=height/workScale+'px',
		chrtrEl = document.getElementById( preId+id );
	chrtrEl.style.width = viewWidth;
	chrtrEl.style.height = viewHeight;
};

function ruleCharacter( e ){
	
	if( e.keyCode>47 && e.keyCode<58 && !e.shiftKey ){
		var newSAct = document.getElementById( 'ActorID'+( e.keyCode-48 ));
		if( newSAct ) selectActors( e, newSAct );
		e.preventDefault();
		return;
	}

	if(selectedActor==null) return;
	var inc = e.ctrlKey ? incMoveActorCtrl : incMoveActor, shiftEl=null;
	switch(e.keyCode){
		case 37://case 65:case 97:
			shiftEl = { shiftLeft: -inc, shiftTop: 0 };
			//selectedActor.style.left = ((parseInt(selectedActor.style.left)||0) - inc) + "px";
			break;
		case 38://case 87:case 119:
			shiftEl = { shiftLeft: 0, shiftTop: -inc };
			//selectedActor.style.top = ((parseInt(selectedActor.style.top)||0) - inc) + "px";
			break;
		case 39://case 68:case 100:
			shiftEl = { shiftLeft: inc, shiftTop: 0 };
			//selectedActor.style.left = ((parseInt(selectedActor.style.left)||0) + inc) + "px";
			break;
		case 40://case 83:case 115:
			shiftEl = { shiftLeft: 0, shiftTop: inc };
			//selectedActor.style.top = ((parseInt(selectedActor.style.top)||0) + inc) + "px";
			break;						
	}
	
	if( shiftEl!=null ){
		//moveCharacter( selectedActor );
		moveGroup( null, shiftEl );
		e.preventDefault();	
	}
};	

	
$(document).ready(function(){
	
	fitScreens();
	
	$('.actor').last().load(function(){
		var incId=0, incTop=0, incLeft=0, rowH=0;
		$('.actor').each(function(){
			var id = 'ActorID'+( incId++ ).toFixed();
				origW = this.offsetWidth, origH = this.offsetHeight,
				scaleW = origW*workScale, scaleH = origH*workScale;

			$(this).attr('id', id)
			.clone().css({'position':'absolute',width:origW+'px', height:origH+'px'})
			.removeClass('actor').addClass('character')
			.attr('id', 'view'+id).attr('title', '' ).appendTo('#view_screen');
			
			$(this).attr('title', this.title+id )
			.css({
				width:scaleW+'px', height:scaleH+'px', 
				top:wscreenH+screenBorderW+incTop+'px', left:incLeft+'px',
				cursor:'move'
			});
			
			incLeft+=scaleW; //сдвиг влево следующего
			if(rowH<scaleH) rowH=scaleH;//высота ряда по самому всокому элементу
			if( incLeft>wscreenW ) {	
				incTop+=rowH+screenBorderW; //сдвиг вниз следующего ряда
				rowH=0; incLeft=0;
			}
				
			moveCharacter( this );	
				
			var onDrag = (function(el){
				return function( shiftEl ){
					moveCharacter( el );
					moveGroup( el, shiftEl );
				}
			})(this);
			setDraggble(this, this, null, onDrag, onDrag );
			
			var onResize = (function(el){
				return function(){
					resizeCharacter( el );
				}
			})(this);
			setResizable( this, { minWidth: 1, minHeight: 1 }, onResize );
			
		});	
	});

	
	Array.prototype.forEach.call( document.querySelectorAll('.actor'), function( el ) {
		addEvent( el, "mousedown", function( e ) {
			draggbleActor=selectedActor=el;
			selectActors( e, el );
		}, false);
	});
	
	addEvent( document, 'mouseup', function(){ draggbleActor=null; } );
	addEvent( document, "keydown", function(e){ ruleCharacter( e ) }, false);
	addEvent( document.getElementById('view_screen'), 'mousemove', function(e){ draggbleActor=null; 
		var e = fixEvent(e);
		infoReg.reg({ screenMouseX: (e.pageX-this.offsetLeft-screenBorderW+1), screenMouseY: (e.pageY-this.offsetTop-screenBorderW+1) });
	});
	
	
});

</script>

<script type="text/javascript">/* Event, Drag, Resize, Info */
function fixEvent(e) {
  e = e || window.event;

  if (!e.target) e.target = e.srcElement;

  if (e.pageX == null && e.clientX != null ) { // если нет pageX..
    var html = document.documentElement;
    var body = document.body;

    e.pageX = e.clientX + (html.scrollLeft || body && body.scrollLeft || 0);
    e.pageX -= html.clientLeft || 0;

    e.pageY = e.clientY + (html.scrollTop || body && body.scrollTop || 0);
    e.pageY -= html.clientTop || 0;
  }

  if (!e.which && e.button) {
    e.which = e.button & 1 ? 1 : ( e.button & 2 ? 3 : ( e.button & 4 ? 2 : 0 ) )
  }

  return e;
}

var addEvent, removeEvent;
if (document.addEventListener) { // проверка существования метода
    addEvent = function(elem, type, handler, capture) {
        elem.addEventListener(type, handler, capture ? true : false)
    }
    removeEvent = function(elem, type, handler, capture) {
        elem.removeEventListener(type, handler, capture ? true : false)
    }
} else {
    addEvent = function(elem, type, handler) {

		var scope = elem._listeners || {},
			listeners = scope[ type ] = scope[ type ] || [],
			proxy = function() {
				handler.call( elem, window.event );
			}
			
		listeners[ listeners.length ] = {
			original: handler,
			proxy: proxy
		}
		elem._listeners = scope;
		
        elem.attachEvent("on" + type, proxy);
    }
    removeEvent = function(elem, type, handler) {
		
		var scope = elem._listeners || {},
			listeners = scope[ type ] || [];
			
		for( var i = listeners.length - 1; i >= 0; i-- ) {
			if ( listeners[ i ].original === handler ) {
				elem.detachEvent( "on" + type, listeners[ i ].proxy );
				listeners.splice( i, 1 );
				break;
			}
		}
    }
}

//--------------------------------
function getCoords(element) {
    var box = element.getBoundingClientRect();

    var body = document.body;
    var docElem = document.documentElement;

    var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
    var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;

    var clientTop = docElem.clientTop || body.clientTop || 0;
    var clientLeft = docElem.clientLeft || body.clientLeft || 0;

    var top  = box.top +  scrollTop - clientTop;
    var left = box.left + scrollLeft - clientLeft;

    return { top: Math.round(top), left: Math.round(left) };
}

function setDraggble( elem, handle, onDragStart, onDrag, onDragEnd ) {
	var handle = handle || elem
		, onDragStart = onDragStart || null
		, onDrag = onDrag || null
		, onDragEnd = onDragEnd || null;
	
	var mousedown = function(e) {
		var self = this;
		e = fixEvent(e); 
		//alert([e.target.sourceIndex,handle.sourceIndex, elem.sourceIndex]);
		//if( e.target!== handle ) return;
		var className = e.target.className; // поймали клик на "ручке" 
		if (className.indexOf("resize-handle-") == 0) return;

		var coords = getCoords(this);
		var coordsP = getCoords(this.parentNode);
		var shiftX = e.pageX - coords.left + coordsP.left;
		var shiftY = e.pageY - coords.top + coordsP.top;

		this.style.position = 'absolute';
		//document.body.appendChild(this);
		//moveAt(e);
		if(typeof onDragStart =="function") onDragStart();

		this.style.zIndex = 1000; // над другими элементами

		function moveAt(e) {
			var oldLeft = parseInt(self.style.left), oldTop = parseInt(self.style.top);
			self.style.left = e.pageX - shiftX + 'px';
			self.style.top = e.pageY - shiftY+ 'px';
			return { shiftLeft: (e.pageX - shiftX)-oldLeft, shiftTop: (e.pageY - shiftY)-oldTop };
		}

		documentMousemove = function(e) {
			e = fixEvent(e);
			shiftEl = moveAt(e); /* сдвиг элемента */
			if(typeof onDrag =="function") onDrag( shiftEl );	
		};
		addEvent( document, 'mousemove', documentMousemove );

		documentMouseup = function() {
			removeEvent( document, 'mousemove', documentMousemove );
			removeEvent( document, 'mouseup', documentMouseup );
			if(typeof onDragEnd =="function") onDragEnd( shiftEl );
		};
		addEvent( document, 'mouseup', documentMouseup );
		
		if( e.preventDefault )  e.preventDefault();
		else e.returnValue = false;	
	}
	addEvent( elem, 'mousedown', mousedown );

	elem.ondragstart = function() { 
		return false; 
	};
}

function setResizable( elem, options, onResize ) {
	var opt={}, defaultOptions = { 
        minWidth: 100, minHeight: 100, maxWidth: screen.width, maxHeight: screen.height
    }
    for(var option in defaultOptions) 
	opt[option] = options && options[option] !==undefined  ? options[option] : defaultOptions[option];
	
  var handleSize = 3;
  
  // добавляем "ручки" в обертку
  var handleS = document.createElement('div');
  handleS.className = 'resize-handle-s';
  handleS.style.cssText = 'height: 3px;width:100%;position: absolute;bottom: 0;cursor: s-resize;';
  elem.appendChild(handleS);

  var handleE = document.createElement('div');
  handleE.className = 'resize-handle-e';
  handleE.style.cssText = 'width: 3px;height:95%;position: absolute;right: 0;bottom: 0;cursor: e-resize;';
  elem.appendChild(handleE);

  var handleSE = document.createElement('div');
  handleSE.className = 'resize-handle-se';
  handleSE.style.cssText = 'width: 25px;height: 25px;position: absolute;bottom: 0;right: 0;cursor: se-resize;';
  elem.appendChild(handleSE);

  addEvent( elem, 'mousedown', function(e) {
    e = fixEvent(e);
	if ( e.target === elem ||
		e.target === handleS ||
		e.target === handleE ||
		e.target === handleSE ) {
	
		var className = e.target.className;
		if (className.indexOf("resize-handle-") == 0) {
		  // поймали клик на "ручке" - вызываем начало ресайза
		  var type = className.slice("resize-handle-".length);
		  startResize(type);
		}
		
		if( e.preventDefault )  e.preventDefault();
		else e.returnValue = false;
	}
  });

  // отменить перенос и выделение браузера
  // в дополнение к return false из mousedown
  elem.onselectstart = elem.ondragstart = function() {
    return false;
  };


  var newWidth, newHeight;
  function startResize(type) {

    document.onmousemove = function(e) {
      e = fixEvent(e);

      var offset = getCoords(elem);

      if (~type.indexOf("s")) {
        // в ручке есть буква "s" - значит меняем высоту 
        newHeight = Math.max(e.pageY - offset.top, handleSize);
		newHeight = Math.min( opt.maxHeight, Math.max( opt.minHeight, newHeight ));
        elem.style.height = newHeight + 'px';
      }
	    if (~type.indexOf("e")) {
        // в ручке есть буква "e" - значит меняем ширину 
        newWidth = Math.max(e.pageX - offset.left, handleSize);
		newWidth = Math.min( opt.maxWidth, Math.max( opt.minWidth, newWidth ));
        elem.style.width = newWidth + 'px';
      }
	  
	  if(typeof onResize =="function") onResize();

    }

    document.onmouseup = function() {
      // конец ресайза
      document.onmousemove = document.onmouseup = null;
	  
    }

  }

}

//------------------------
var infoReg={
	info:{}
	,reg: function( info ){ for(var key in info) this.info[ key ]=info[ key ]; this.show(); }
	,show: function(){ 
		for(var key in this.info){
			var el = document.getElementById( key );
			if( el!=null ) el.innerHTML = this.info[ key ];
		} 
	}
};

</script>
  
<style type="text/css">
 body{background-color: #DDD}
.float_l{ float:left; } 
.float_r{ float:right; } 
.clear_both{ clear:both }
#film_splicer{ margin: 0 20px; width_:50%; position: relative}
#view_screen{
border: 1px solid navy;
}
#view_screen{
	overflow: hidden; z-index: 10000; position:relative;background-color: #FFF;
	box-sizing: content-box;
}
#work_screen{
	top:0;left:0; border: 1px solid white; /* position:absolute; */
}

.actor, .character{position:absolute;}
.actor{ border: 1px solid white;}
.selectedActor{ border: 1px solid red;}
.resize-handle-s, .resize-handle-e{ background-color: navy; }

#setting_panel input{width: 100px}

#effects_panel{ width: 400px }
.effect_div{ padding: 3px; border: 1px solid navy; float:left;}
	.effect_div input{width: 50px}
	.effect_div input[type="button"]{width: 100px}
	.effect_div input[type="checkbox"]{width: 20px}
	.effect_div .w100{width: 100px}
	.effect_div .w200{width: 200px}
	.effect_div .w400{width: 400px}

.ws_border{ border: 1px solid white; z-index: 10000; position: absolute; cursor:crosshair; opacity: 0.7}
	.ws_border.top{ width:99%; top:0px}
	.ws_border.right{ height:98%; right:0px; bottom:0px;}
	.ws_border.bottom{ width:99%; bottom:0px; right:0px; }
	.ws_border.left{ height:98%; left:0px }
	.ws_border.middleVert{ height:99%; left:50% }
	.ws_border.middleHorz{ width:99%; top:50% }
 
.scr560_315 { width:560px; height: 315px; }
.scr640_360 { width:640px; height: 360px; }
.scr853_480 { width:853px; height: 480px; } .scr85_48 { width:214px; height: 120px; } 
.scr1280_720 { width:1280px; height: 720px; }
</style>
</head>
 <body>

<div id="view_screen" class="float_l" data-desc="Экран просмотра"></div>

<div id="film_splicer" class="float_r" data-desc="Монтажный стол">
	<div id="work_screen" class="" data-desc="Экран рабочий">
		<div class="ws_border top"></div>
		<div class="ws_border right"></div>
		<div class="ws_border bottom"></div>
		<div class="ws_border left"></div>
		<div class="ws_border middleVert"></div>
		<div class="ws_border middleHorz"></div>
	</div>


	
	<!--div style="width: 300px;" class="actor">
		<video autoplay width="100%" height_="300" controls="controls">
			<!--source src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4" type="video/mp4"  /><!-- Safari / iOS, IE9 -->
			<!--source src="http://clips.vorwaerts-gmbh.de/VfE.webm"      type="video/webm" /><!-- Chrome10+, Ffx4+, Opera10.6+ -->
			<!--source src="http://clips.vorwaerts-gmbh.de/VfE.ogv"       type="video/ogg"  /><!-- Firefox3.6+ / Opera 10.5+ >
		</video>
	</div-->
	<img src="http://denis-or-love.narod.ru/spacebgs/Space__000834_1.jpg" title="Тарелка " class="actor"/>
	<div style="background-color: #DD0" contenteditable="true" class="actor scr85_48">Привет!</div>
	<img src="http://yves.marsal.free.fr/atoutgifs/yespace45.gif" title="Тарелка " class="actor"/>
	<img src="http://www.smayli.ru/data/smiles/transporta-854.gif" title="Шар " class="actor"/>
	<div style="width: 300px;" title="Самолет " class="actor"><!-- resize block -->
		<img src="http://www.smayli.ru/data/smiles/transporta-807.gif" width="100%"/>
	</div>
	<script>for(var i=2;i<3;i++) document.write('<img src="http://www.smayli.ru/data/smiles/transporta-'+i+'.gif" title="Самолет " class="actor"/>');</script>
	
</div>
	<div class="float_l">
		<input type="checkbox" title="Syncronization" onclick="if(this.checked)setInterval( fitActorsByCharacters, 100);">
	</div>
<div class="clear_both"></div>

<div id="setting_panel">
	<div class="float_l">
		<input type="text" value="853" id="screenW">
		<input type="text" value="480" id="screenH">
		X: <span id="screenMouseX"></span>
		Y: <span id="screenMouseY"></span><br>
		<input type="text" value="0.3" id="workScale">
		<input type="text" value="1" id="screenBorderW">
		<input type="button" onclick="fitScreens();" value="Fit Screens">
	</div>
	<div class="float_l">
		<input type="button" onclick="addCycle();" value="Add CyclePan">
	</div>
</div>
<div class="clear_both"></div>

<div id="effects_panel" class="">

</div>
<script>
var effects = {	
	fadeOut:{
		html: '<input type="text" id="fadeOut-duration" value="2000">'+
			'<input type="button" onclick="effects.fadeOut.fn();" value="FadeOut" title="'+
			'Изчезание: длительность'+'">',
		fn: function(){ 
			applyCharacters( function( character ){ $( character ).fadeOut( +$('#fadeOut-duration').val() ); } );
		}
	}
	,fadeIn:{
		html: '<input type="text" id="fadeIn-duration" value="4000">'+
			'<input type="button" onclick="effects.fadeIn.fn();" value="FadeIn" title="'+
			'Появление: длительность'+'">',
		fn: function(){ 
			applyCharacters( function( character ){ $( character ).fadeIn( +$('#fadeIn-duration').val()); } );
		}
	}

	,animate:{
		html: '<input type="text" class="w200" id="animate-props" value="top,left">'+//'<br>'+
			'<input type="text" class="w200" id="animate-vals" value="100px,300px">'+//'<br>'+
			'<input type="text" id="animate-duration" value="2000">'+
			'<input type="button" onclick="effects.animate.fn();" value="Animate" title="'+
			'Анимация: свойства, значения, длительность( значения через &quot;,&quot; )'+'">',
		fn: function(){ 
			var properties = {},
				props = $('#animate-props').val().replace( /\s/g, '' ).split(','),
				vals = $('#animate-vals').val().replace( /\s/g, '' ).split(','),
				duration = $('#animate-duration').val() || 1000;
			for(var i=0; i<props.length; i++ ) properties[ props[i] ] = vals[i];
			applyCharacters( function( character ){ $( character ).animate( properties, +duration ); } );
		}
	}
	
	,cycle:{ 
		html: '<input type="text" class="w200" id="cycle-props" value="top,left;top,left;top,left;top,left">'+//'<br>'+
			'<input type="text" class="w200" id="cycle-vals" value="10px,10px;10px,300px;300px,300px;300px,10px;">'+//'<br>'+
			'<input type="text" class="w200" id="cycle-durations" value="2000;500;100;1000">'+
			//'<input type="button" onclick="effects.cycle.refresh();" value="Refresh">'+
			'<input type="checkbox" id="cycle-cycleOn" value="1" checked="checked">'+
			'<input type="button" id="cycle-button-on" onclick="effects.cycle.on();" value="Start" title="'+
			'Цикл: свойства, значения, длительности( значения через &quot;,&quot;,  группы значений через &quot;;&quot; ), цикличность, кнопки: обновить, запустить'+'">',
		step:[], stepCurrent: 0, timeOutID: null, timeOutFunc: null, 
		refresh: function(){ 
			effects.cycle.step = []; 
			var 
				props = $('#cycle-props').val().replace( /\s/g, '' ).split(';'),
				vals = $('#cycle-vals').val().replace( /\s/g, '' ).split(';'),
				durs = $('#cycle-durations').val().replace( /\s/g, '' ).split(';');
			for(var i=0; i<props.length; i++ ) 
				effects.cycle.step.push( {prop:props[i], val:vals[i], dur: +( durs[i] || 1000)} );
			effects.cycle.stepCurrent=0;
		},
		stop: function(){
				clearInterval( effects.cycle.timeOutID ); 
				effects.cycle.timeOutID=null;
				applyCharacters( function( character ){ $( character ).stop(); } );
				// следующий шаг - текущий недоделанный
				effects.cycle.stepCurrent = effects.cycle.stepCurrent == 0 ? effects.cycle.step.length-1 : effects.cycle.stepCurrent-1;
				$('#cycle-button-on').val('Start');
			},
		on: function(){
			if( effects.cycle.timeOutID!==null ) {// выключаем
				effects.cycle.stop();
				return;
			}
			
			//if( effects.cycle.step.length<1) //если пусто
				effects.cycle.refresh(); //обновляем 
			if( effects.cycle.step.length<1) return; //выходим если пусто
			
			effects.cycle.timeOutFunc = function(){
				var stepObj = effects.cycle.step[ effects.cycle.stepCurrent ],//берем объект свойств текущего шага
					props = stepObj.prop.split(','),
					vals = stepObj.val.split(','),
					duration = stepObj.dur, 
					properties  = {};
				for(var i=0; i<props.length; i++ ) properties[ props[i] ] = vals[i];
				applyCharacters( function( character ){ $( character ).animate( properties, +duration ); } );

				effects.cycle.stepCurrent = effects.cycle.stepCurrent+1<effects.cycle.step.length ? effects.cycle.stepCurrent+1 : 0;// следующий шаг
				var cycleOn = document.getElementById('cycle-cycleOn').checked;
				
				if( effects.cycle.stepCurrent==0 && !cycleOn ){
					effects.cycle.stop();
					effects.cycle.stepCurrent=0;
					return;
				}
				effects.cycle.timeOutID = setTimeout( effects.cycle.timeOutFunc,  duration ); //
			};
			
			//var duration = effects.cycle.step[ effects.cycle.stepCurrent ].dur;
			$('#cycle-button-on').val('Stop');
			effects.cycle.timeOutID = setTimeout( effects.cycle.timeOutFunc,  0 );	
		}
	}
}
//for(var i=2;i<30;i++)
for(var key in effects){
	var eff = effects[key];
		$('<div class="effect_div"></div>').html( effects[key].html ).appendTo('#effects_panel');	
}

//------------------------------------------
function CycleSelector( objName ){
	
	this.html= '<input type="text" class="w400" id="'+objName+'-props" value="left,top;left,top;left,top;left,top">'+
		'<input type="text" class="w400" id="'+objName+'-vals" value="10px,10px;10px,300px;300px,300px;300px,10px;">'+'<br>'+
		'<input type="text" class="w400" id="'+objName+'-durations" value="2000;500;1000;1500">'+
		'<input type="text" class="w200" id="'+objName+'-selector" value="#viewActorID2">'+
		//'<input type="button" onclick="'+objName+'.refresh();" value="Refresh">'+
		'<input type="checkbox" id="'+objName+'-cycleOn" value="1" checked="checked">'+
		'<input type="button" id="'+objName+'-button-on" onclick="'+objName+'.on();" value="Start" title="'+
		'Цикл: свойства, значения, длительности( значения через &quot;,&quot;,  группы значений через &quot;;&quot; ), селектор, кнопки: обновить, запустить'+'">';
	this.step=[]; this.stepCurrent= 0; this.timeOutFunc= null; this.selector= null;
	this.refresh= function(){ 
		this.step = [];
		this.selector = document.getElementById(objName+'-selector').value;
			if( this.selector=='' ) return;
		var props = document.getElementById(objName+'-props').value.replace( /\s/g, '' ).split(';'),
			vals = document.getElementById(objName+'-vals').value.replace( /\s/g, '' ).split(';'),
			durs = document.getElementById(objName+'-durations').value.replace( /\s/g, '' ).split(';');
		
		for(var i=0; i<props.length; i++ ) 
			this.step.push( {prop:props[i], val:vals[i], dur: +( durs[i] || 1000)} );
		this.stepCurrent=0;
	};
	this.stop= function(){
		$( this.selector ).stop( true, false );
		// следующий шаг - текущий недоделанный
		this.stepCurrent = this.stepCurrent == 0 ? this.step.length-1 : this.stepCurrent-1;
		document.getElementById(objName+'-button-on').value='Start';
	};
	this.on= function(){
		if ( $( this.selector + ":animated" ).length ) {
			this.stop();
			return;
		}
		
		//if( this.step.length<1) //если пусто
			this.refresh(); //обновляем 
		if( this.step.length<1) return; //выходим если пусто
		
		var this_ = this;
		var timeOutFunc = function(  ){
			var stepObj = this_.step[ this_.stepCurrent ],//берем объект свойств текущего шага
				props = stepObj.prop.split(','),
				vals = stepObj.val.split(','),
				duration = stepObj.dur, 
				properties  = {}; //console.log(this_.stepCurrent+': '+stepObj.val);
			for(var i=0; i<props.length; i++ ) properties[ props[i] ] = vals[i];
			
			this_.stepCurrent = this_.stepCurrent+1<this_.step.length ? this_.stepCurrent+1 : 0;// следующий шаг
			var cycleOn = document.getElementById( objName+'-cycleOn' ).checked;
			
			if( this_.stepCurrent==0 && !cycleOn ){
				var completeFunc = function(){
					this_.stop();
					this_.stepCurrent=0;
				}
			}else{
				var completeFunc = timeOutFunc;
			};
			
			$( this_.selector ).animate( properties, {
				duration: +duration,
				complete: completeFunc,
			});

		};
		
		document.getElementById(objName+'-button-on').value='Stop';
		timeOutFunc();
	};
}

var cycles = [];
function addCycle(){
	var cycle = new CycleSelector('cycles['+cycles.length+']');
	cycles.push( cycle );
	$('<div class="effect_div"></div>').html( cycle.html ).appendTo('#effects_panel');
}
	
</script>


 </body>
</html>